package file

import (
	"crypto/md5"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"time"
	"xServer/config"
	"xServer/internal/model"
	"xServer/internal/utils"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

// CreateDirectory 创建目录
func CreateDirectory(c *gin.Context) {
	// 获取用户ID（假设从认证中间件获取）
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 绑定请求参数
	var req struct {
		Name     string `json:"name" binding:"required"`
		ParentID uint   `json:"parent_id,string"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误: " + err.Error()})
		return
	}

	// 检查目录名称是否已存在
	var existingDir model.Directory
	if err := utils.DB.Where("name = ? AND parent_id = ? AND user_id = ?", req.Name, req.ParentID, userID).First(&existingDir).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
		c.JSON(http.StatusConflict, gin.H{"error": "目录名称已存在"})
		return
	}

	// 创建新目录
	directory := model.Directory{
		Name:     req.Name,
		ParentID: req.ParentID,
		UserID:   userID.(uint),
	}

	if err := utils.DB.Create(&directory).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "创建目录失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "目录创建成功", "directory": directory})
}

// ListDirectories 列出目录
func ListDirectories(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取父目录ID（可选）
	parentID := c.Query("parent_id")

	// 查询目录
	var directories []model.Directory
	query := utils.DB.Where("user_id = ?", userID)

	if parentID != "" {
		query = query.Where("parent_id = ?", parentID)
	} else {
		// 如果没有提供parent_id，查询顶级目录
		query = query.Where("parent_id IS NULL OR parent_id = 0")
	}

	if err := query.Find(&directories).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "获取目录列表失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"directories": directories})
}

// GetDirectory 获取目录详情
func GetDirectory(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取目录ID
	dirID := c.Param("id")

	// 查询目录
	var directory model.Directory
	if err := utils.DB.Where("id = ? AND user_id = ?", dirID, userID).First(&directory).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "目录不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "获取目录详情失败: " + err.Error()})
		}
		return
	}

	c.JSON(http.StatusOK, gin.H{"directory": directory})
}

// UpdateDirectory 更新目录
func UpdateDirectory(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取目录ID
	dirID := c.Param("id")

	// 绑定请求参数
	var req struct {
		Name string `json:"name" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误: " + err.Error()})
		return
	}

	// 查询目录
	var directory model.Directory
	if err := utils.DB.Where("id = ? AND user_id = ?", dirID, userID).First(&directory).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "目录不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "获取目录详情失败: " + err.Error()})
		}
		return
	}

	// 检查目录名称是否已存在
	var existingDir model.Directory
	if err := utils.DB.Where("name = ? AND parent_id = ? AND user_id = ? AND id != ?",
		req.Name, directory.ParentID, userID, dirID).First(&existingDir).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
		c.JSON(http.StatusConflict, gin.H{"error": "目录名称已存在"})
		return
	}

	// 更新目录
	directory.Name = req.Name
	if err := utils.DB.Save(&directory).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "更新目录失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "目录更新成功", "directory": directory})
}

// DeleteDirectory 删除目录
func DeleteDirectory(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取目录ID
	dirID := c.Param("id")

	// 查询目录
	var directory model.Directory
	if err := utils.DB.Where("id = ? AND user_id = ?", dirID, userID).First(&directory).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "目录不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "获取目录详情失败: " + err.Error()})
		}
		return
	}

	// 检查目录是否为空
	var subDirCount int64
	utils.DB.Model(&model.Directory{}).Where("parent_id = ?", dirID).Count(&subDirCount)

	var fileCount int64
	utils.DB.Model(&model.File{}).Where("directory_id = ?", dirID).Count(&fileCount)

	if subDirCount > 0 || fileCount > 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "目录不为空，无法删除"})
		return
	}

	// 删除目录
	if err := utils.DB.Delete(&directory).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "删除目录失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "目录删除成功"})
}

// ListFilesInDirectory 获取目录下文件列表
func ListFilesInDirectory(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取目录ID
	dirID := c.Param("directory_id")

	// 验证目录是否存在且属于当前用户
	var directory model.Directory
	if err := utils.DB.Where("id = ? AND user_id = ?", dirID, userID).First(&directory).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "目录不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "获取目录详情失败: " + err.Error()})
		}
		return
	}

	// 查询目录下的文件
	var files []model.File
	if err := utils.DB.Where("directory_id = ?", dirID).Find(&files).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "获取文件列表失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"files": files})
}

// UploadFile 上传文件
func UploadFile(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取目录ID
	dirID := c.PostForm("directory_id")
	if dirID == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "目录ID不能为空"})
		return
	}

	// 验证目录是否存在且属于当前用户
	var directory model.Directory
	if err := utils.DB.Where("id = ? AND user_id = ?", dirID, userID).First(&directory).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "目录不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "获取目录详情失败: " + err.Error()})
		}
		return
	}

	// 获取上传的文件
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "获取文件失败: " + err.Error()})
		return
	}
	defer file.Close()

	// 检查文件是否已存在
	var existingFile model.File
	if err := utils.DB.Where("name = ? AND directory_id = ?", header.Filename, dirID).First(&existingFile).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
		c.JSON(http.StatusConflict, gin.H{"error": "文件已存在"})
		return
	}

	// 计算文件的 MD5
	hash := md5.New()
	_, err = io.Copy(hash, file)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "计算MD5失败: " + err.Error()})
		return
	}
	md5Sum := fmt.Sprintf("%x", hash.Sum(nil))

	// 将前6位拆分为 12/34/56 格式
	md5Prefix := md5Sum[:6]
	var dirStructure string
	for i := 0; i < 3; i++ {
		start := i * 2
		end := start + 2
		dirStructure = filepath.Join(dirStructure, md5Prefix[start:end])
	}

	// 重置文件指针以便再次读取
	_, err = file.(io.Seeker).Seek(0, io.SeekStart)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "无法重置文件指针: " + err.Error()})
		return
	}

	// 构建存储路径
	storageRoot := config.AppConfig.Storage.RootPath
	finalPath := filepath.Join(storageRoot, dirStructure)

	// 创建多级目录
	if err := os.MkdirAll(finalPath, os.ModePerm); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "创建目录失败: " + err.Error()})
		return
	}

	// 文件最终保存路径
	filePath := filepath.Join(finalPath, header.Filename)

	// 保存上传的文件
	dst, err := os.Create(filePath)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "创建目标文件失败: " + err.Error()})
		return
	}
	defer dst.Close()

	if _, err := io.Copy(dst, file); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "写入文件失败: " + err.Error()})
		return
	}

	// 创建文件记录
	newFile := model.File{
		Name:        header.Filename,
		Size:        header.Size,
		FilePath:    filePath,
		DirectoryID: directory.ID,
		UserID:      userID.(int),
		MD5:         md5Sum,
	}

	if err := utils.DB.Create(&newFile).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "创建文件记录失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message": "文件上传成功",
		"code":    200,
		"file":    newFile,
	})
}

// GetFile 获取文件详情
func GetFile(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取文件ID
	fileID := c.Param("id")

	// 查询文件
	var file model.File
	if err := utils.DB.Where("id = ? AND user_id = ?", fileID, userID).First(&file).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "获取文件详情失败: " + err.Error()})
		}
		return
	}

	c.JSON(http.StatusOK, gin.H{"file": file})
}

// UpdateFile 更新文件
func UpdateFile(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取文件ID
	fileID := c.Param("id")

	// 绑定请求参数
	var req struct {
		Name string `json:"name" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误: " + err.Error()})
		return
	}

	// 查询文件
	var file model.File
	if err := utils.DB.Where("id = ? AND user_id = ?", fileID, userID).First(&file).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "获取文件详情失败: " + err.Error()})
		}
		return
	}

	// 检查文件名是否已存在
	var existingFile model.File
	if err := utils.DB.Where("name = ? AND directory_id = ? AND id != ?",
		req.Name, file.DirectoryID, fileID).First(&existingFile).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
		c.JSON(http.StatusConflict, gin.H{"error": "文件名已存在"})
		return
	}

	// 更新文件
	file.Name = req.Name
	if err := utils.DB.Save(&file).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "更新文件失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "文件更新成功", "file": file})
}

// DeleteFile 删除文件
func DeleteFile(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取文件ID
	fileID := c.Param("id")

	// 查询文件
	var file model.File
	if err := utils.DB.Where("id = ? AND user_id = ?", fileID, userID).First(&file).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "获取文件详情失败: " + err.Error()})
		}
		return
	}

	// 删除文件
	if err := utils.DB.Delete(&file).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "删除文件记录失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "文件删除成功"})
}

// DownloadPublicFile 公开下载文件
func DownloadPublicFile(c *gin.Context) {
	// 获取访问令牌
	accessToken := c.Query("token")
	if accessToken == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "访问令牌不能为空"})
		return
	}

	// 查询访问令牌
	var token model.AccessToken
	if err := utils.DB.Where("token = ? AND expired_at > NOW()", accessToken).First(&token).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "无效的访问令牌或令牌已过期"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "查询访问令牌失败: " + err.Error()})
		}
		return
	}

	// 查询文件
	var file model.File
	if err := utils.DB.Where("id = ?", token.FileID).First(&file).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "查询文件失败: " + err.Error()})
		}
		return
	}

	// 提供文件下载
	c.File(file.FilePath)
}

// DownloadFile 用户文件下载
func DownloadFile(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取文件ID
	fileID := c.Param("id")

	// 查询文件
	var file model.File
	if err := utils.DB.Where("id = ? AND user_id = ?", fileID, userID).First(&file).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "查询文件失败: " + err.Error()})
		}
		return
	}

	// 设置响应头，指定下载文件名（使用原始文件名）
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(file.Name)) // 关键修改点

	// 提供文件内容作为下载
	c.File(file.FilePath)
}

// GenerateAccessToken 生成文件访问令牌
func GenerateAccessToken(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取文件ID和过期时间
	var req struct {
		FileID    uint   `json:"file_id" binding:"required"`
		ExpiresIn int    `json:"expires_in" binding:"required,min=1"` // 过期时间（分钟）
		Remark    string `json:"remark"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误: " + err.Error()})
		return
	}

	// 验证文件是否存在且属于当前用户
	var file model.File
	if err := utils.DB.Where("id = ? AND user_id = ?", req.FileID, userID).First(&file).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "查询文件失败: " + err.Error()})
		}
		return
	}

	// 生成访问令牌
	accessToken := utils.GenerateRandomStringWithCharset(32)
	expiredAt := time.Now().Add(time.Duration(req.ExpiresIn) * time.Minute)

	// 创建访问令牌记录
	token := model.AccessToken{
		Token:     accessToken,
		FileID:    req.FileID,
		UserID:    userID.(int),
		ExpiresAt: expiredAt,
		Remark:    req.Remark,
	}

	if err := utils.DB.Create(&token).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "创建访问令牌失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message":      "访问令牌生成成功",
		"access_token": accessToken,
		"expired_at":   expiredAt.Format(time.RFC3339),
	})
}

// DirectoryDetail 获取目录详情（包含子目录和文件）
// @Summary 获取目录详情
// @Description 获取指定路径目录的详情，包括子目录和文件列表
// @Tags directory
// @Accept json
// @Produce json
// @Param path query string true "目录路径"
// @Success 200 {object} utils.Response{data=DirectoryDetailResponse}
// @Failure 400 {object} utils.Response
// @Failure 401 {object} utils.Response
// @Failure 500 {object} utils.Response
// @Router /api/directories/detail [get]
func DirectoryDetail(c *gin.Context) {
	// 获取用户ID
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	// 获取路径参数
	path := c.Query("path")
	if path == "" {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "路径参数不能为空: "})
		return
	}

	// 查询目录
	var dir model.Directory

	result := utils.DB.Where("user_id = ? AND name = ?", userID, path).First(&dir)
	if errors.Is(result.Error, gorm.ErrRecordNotFound) {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "目录不存在: "})
		return
	} else if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "查询目录失败: "})
		return
	}

	// 查询子目录
	var subDirs []model.Directory
	utils.DB.Where("user_id = ? AND parent_id = ?", userID, dir.ID).Find(&subDirs)

	// 查询文件
	var files []model.File
	utils.DB.Where("user_id = ? AND directory_id = ?", userID, dir.ID).Find(&files)

	// 构建响应
	response := DirectoryDetailResponse{
		Directory:   dir,
		Directories: subDirs,
		Files:       files,
	}

	c.JSON(http.StatusOK, gin.H{
		"message": "获取成功",
		"code":    200,
		"data":    response,
	})
}

// 定义响应结构体
type DirectoryDetailResponse struct {
	Directory   model.Directory   `json:"directory"`
	Directories []model.Directory `json:"directories"`
	Files       []model.File      `json:"files"`
}
